/*
 * Range.cs
 *
 * Copyright (c) 2005, dnAnalytics. All rights reserved.
 */

using System;
using System.Collections.Generic;
using System.Text;
using dnAnalytics.Resources;

namespace dnAnalytics.LinearAlgebra {
   	/// <summary>
   	/// Defines a range of elements.
   	/// </summary>
    [Serializable]
	public struct Range {
		#region Fields

		private readonly int start;
		private readonly int end;
		private readonly int stride;

		#endregion Fields

		#region Properties

		/// <summary>
		/// Returns the starting point.
		/// </summary>
		/// <value>The starting point.</value>
		public int Start {
			get { return start; }
		}

		/// <summary>
		/// Returns the ending point.
		/// </summary>
		/// <value>The ending point.</value>
		public int End {
			get { return end; }
		}

		/// <summary>
		/// Returns the stride.
		/// </summary>
        /// <remarks>
        /// TODO: EXPLAIN WHAT STRIDE MEANS!
        /// </remarks>
		/// <value>The stride.</value>
		public int Stride {
			get { return stride; }
		}

		#endregion Properties

		#region Constructors

		/// <summary>
        /// Constructs a <b>Range</b> instance with the given starting and ending points.
		/// </summary>
        /// <param name="start">The starting point of the <b>Range</b>.</param>
        /// <param name="end">The ending point of the <b>Range</b>.</param>
		public Range(int start, int end) : this(start, end, 1) {}

		/// <summary>
        /// Constructs a <b>Range</b> instance with the given start and ending points, and 
		/// a stride (the size of the step between the points).
		/// </summary>
        /// <param name="start">The starting point of the <b>Range</b>.</param>
        /// <param name="end">The ending point of the <b>Range</b>.</param>
		/// <param name="stride">The size of the step between the points.</param>
		/// <exception cref="ArgumentException">if start &gt; end or stride &lt; 1.</exception>
		public Range(int start, int end, int stride) {
			if (start < 0) {
				throw new ArgumentException(Strings.NotPositiveException, "start"); 
			}

			if (start > end) {
				throw new ArgumentException(Strings.StartGTEnd);
			}

			if (stride < 1) {
				throw new ArgumentException(Strings.NotPositiveException, "stride");
			}

			this.start = start;
			this.end = end;
			this.stride = stride;
		}

		#endregion Constructores

		#region Public Members

		/// <summary>
        /// Returns the string representation of this <b>Range</b>.
		/// </summary>
        /// <returns>The string representation of this <b>Range</b></returns>
		public override string ToString() {
			return "start: " + start + ", end: " + end + ", stride: " + stride;
		}

		/// <summary>
        /// Compares two <b>Range</b> objects for equality. Two <b>Range</b> objects are equal if there
		/// start, end, stride values are equal.
		/// </summary>
		/// <param name="obj">The object to compare with.</param>
		/// <returns><b>true</b> if the values for start, end, and stride are equal, <b>false</b> otherwise.</returns>
		public override bool Equals(object obj) {
			if (obj == null) {
				return false;
			}
			if (obj is Range) {
				Range other = (Range) obj;
				return this.start == other.start && this.end == other.end && this.stride == other.stride;
			}
			return false;
		}

		/// <summary>
        /// Compares two <b>Range</b> objects for equality. Two <b>Range</b> objects are equal if there
		/// start, end, stride values are equal.
		/// </summary>
		/// <param name="leftSide">The first of the ranges to compare.</param>
		/// <param name="rightSide">The second of the ranges to compare.</param>
		/// <returns><b>true</b> if the values for start, end, and stride are equal, <b>false</b> otherwise.</returns>
		public static bool operator==(Range leftSide, Range rightSide) {
			return leftSide.Equals(rightSide);
		}

		/// <summary>
        /// Checks if two <b>Range</b> objects are not equal. Two <b>Range</b> objects are equal if there
		/// start, end, stride values are equal.
		/// </summary>
		/// <param name="leftSide">The first of the ranges to compare.</param>
		/// <param name="rightSide">The second of the ranges to compare.</param>
		/// <returns><b>true</b> if the values for start, end, and stride are not equal, <b>false</b> otherwise.</returns>
		public static bool operator!=(Range leftSide, Range rightSide) {
			return !leftSide.Equals(rightSide);
		}

		/// <summary>
		/// Calculates the hashcode for this <b>Range</b> object.
		/// </summary>
		/// <returns><b>(end-start)^stride</b> as the hashcode.</returns>
		public override int GetHashCode() {
			return (end-start)^stride;
		}


		#endregion
    }
}
